﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using FinApp.Core;
using System.Runtime.Serialization.Json;
using FinApp.Model;
using FinApp.DataProviders.Configuration;
using FinApp.DataProviders.EventArguments;
using FinApp.DataProviders.Enumerations;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
using System.Device.Location;
using System.Globalization;

namespace FinApp.DataProviders {
    public class CommerceProvider : Singleton<CommerceProvider> {

        #region Events
        public event CommerceCompleteEventHandler CommerceCompleted;
        public event PositionChangedEventHandler PositionChanged;
        #endregion

        #region Members
        private DataContractJsonSerializer commerceIdSerializer;
        private DataContractJsonSerializer commerceSerializer;
        private DataContractJsonSerializer commercePromotionIdsSerializer;
        private string commerceInfoLock;
        private Dictionary<int, AutoResetEvent> commerceInfoDictionary = new Dictionary<int, AutoResetEvent>();
        private Dictionary<int, AutoResetEvent> commerceOffersDictionary = new Dictionary<int, AutoResetEvent>();
        private int indexCommerceId = 0;
        private List<string> commerceIds;
        private ObservableCollection<CommerceDataModel> commerceData;
        private GeoCoordinateWatcher geoCoordinateWatcher;
        #endregion

        #region Constructors
        public CommerceProvider() {
            this.commerceIdSerializer = new DataContractJsonSerializer(typeof(CommerceIdModel));
            this.commerceSerializer = new DataContractJsonSerializer(typeof(CommerceModel));
            this.commercePromotionIdsSerializer = new DataContractJsonSerializer(typeof(CommercePromotionIdsModel));
            this.geoCoordinateWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
            this.geoCoordinateWatcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(OnPositionChanged);
        }
        #endregion

        #region Methods

        public void GetCommerces() {
            if (this.geoCoordinateWatcher.Status != GeoPositionStatus.Ready) {
                this.geoCoordinateWatcher.Start();
            }
        }
        #endregion

        #region Events
        private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e) {
            WebClient webClient = sender as WebClient;
            webClient.OpenReadCompleted -= new OpenReadCompletedEventHandler(OnOpenReadCompleted);
            CommerceIdModel commerceIdModel = (CommerceIdModel)commerceIdSerializer.ReadObject(e.Result);
            if (commerceIdModel.Status == "OK") {
                commerceIds = commerceIdModel.CommerceIds;
                if (indexCommerceId < commerceIds.Count) {

                    WebClient commerceInfoWebClient = sender as WebClient;
                    commerceInfoWebClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OnOpenCommerceInfoReadCompleted);
                    commerceInfoWebClient.OpenReadAsync(new Uri(ConfigurationProvider.Instance.GetApiLoggedInUrl() + string.Format("/operations/commerce/{0}", commerceIds[indexCommerceId++])));
                }
            }
        }

        private void OnPositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) {
            this.geoCoordinateWatcher.Stop();
            if (this.PositionChanged != null) {
                this.PositionChanged(this, new PositionEventArgs(e.Position.Location));
            }
            WebClient webClient = new WebClient();
            webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OnOpenReadCompleted);
            webClient.OpenReadAsync(new Uri(ConfigurationProvider.Instance.GetApiLoggedInUrl() + string.Format("/operations/commerce/search/near?lat={0}&lng={1}&radius={2}", e.Position.Location.Latitude.ToString(CultureInfo.InvariantCulture), e.Position.Location.Longitude.ToString(CultureInfo.InvariantCulture), 0.9.ToString(CultureInfo.InvariantCulture))));
        }

        private void OnOpenCommerceInfoReadCompleted(object sender, OpenReadCompletedEventArgs e) {
            WebClient webClient = sender as WebClient;
            webClient.OpenReadCompleted -= new OpenReadCompletedEventHandler(OnOpenReadCompleted);
            CommerceModel commerceModel = (CommerceModel)commerceSerializer.ReadObject(e.Result);
            if (this.CommerceCompleted != null) {
                switch (commerceModel.Status) {
                    case "OK":
                        this.CommerceCompleted(this, new CommerceEventArgs(ProviderResponseEnumeration.OK, string.Empty, commerceModel.CommerceDataModel));
                        break;
                    default:
                        this.CommerceCompleted(this, new CommerceEventArgs(ProviderResponseEnumeration.Failed, commerceModel.Msg, null));
                        break;
                }
            }
            if (indexCommerceId < commerceIds.Count) {
                try {
                    WebClient commerceInfoWebClient = sender as WebClient;
                    commerceInfoWebClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OnOpenCommerceInfoReadCompleted);
                    commerceInfoWebClient.OpenReadAsync(new Uri(ConfigurationProvider.Instance.GetApiLoggedInUrl() + string.Format("/operations/commerce/{0}", commerceIds[indexCommerceId++])));
                } catch {

                }
            }
        }

        private void OnOpenCommerceOffersReadCompleted(object sender, OpenReadCompletedEventArgs e) {
            WebClient webClient = sender as WebClient;
            webClient.OpenReadCompleted -= new OpenReadCompletedEventHandler(OnOpenReadCompleted);
            CommercePromotionIdsModel commercePromotionIdsModel = (CommercePromotionIdsModel)commercePromotionIdsSerializer.ReadObject(e.Result);
            if (commercePromotionIdsModel.Status == "OK") {

                commerceOffersDictionary[webClient.GetHashCode()].Set();
            }
        }
        #endregion

    }
}
